import * as React from 'react';
import Dialog from 'rc-dialog';
import classnames from 'classnames';
import addEventListener from './addEventListener';
import useFrameSetState from './hooks/useFrameSetState';
import { getFixScaleEleTransPosition } from '../_common/util';

const { useState, useEffect, useMemo, useContext } = React;

import './style/index.less';

import {
  RotateLeftOutlined,
  RotateRightOutlined,
  LeftOutlined,
  RightOutlined,
  CloseOutlined,
  ZoomInOutlined,
  ZoomOutOutlined,
} from '@ant-design/icons';
import { FullScreenPreviewProps } from './interface';
import ImgViewContext from '@/biz-components/img-view/context';

const initialPosition = {
  x: 0,
  y: 0,
};

const FullScreenPreview: React.FC<FullScreenPreviewProps> = (props) => {
  const { onClose, visible, images } = props;

  const prefixCls = 'image-preview';

  const { currentIndex: currentPreviewIndex, nextFn, prevFn } = useContext(ImgViewContext);

  const [scale, setScale] = useState(1);
  const [rotate, setRotate] = useState(0);
  const [position, setPosition] = useFrameSetState<{
    x: number;
    y: number;
  }>(initialPosition);
  const imgRef = React.useRef<HTMLImageElement>();
  const originPositionRef = React.useRef<{
    originX: number;
    originY: number;
    deltaX: number;
    deltaY: number;
  }>({
    originX: 0,
    originY: 0,
    deltaX: 0,
    deltaY: 0,
  });
  const [isMoving, setMoving] = React.useState(false);

  const { src: combinationSrc, alt } = useMemo(() => {
    const record = images[currentPreviewIndex];

    if (record) {
      return typeof record === 'string' ? { src: record, alt: '' } : record;
    }

    return  { src: "", alt: '' }

  }, [currentPreviewIndex, images]);

  const [lastWheelZoomDirection, setLastWheelZoomDirection] = React.useState({ wheelDirection: 0 });

  const handleAfterClose = () => {
    setScale(1);
    setRotate(0);
    setPosition(initialPosition);
  };

  const handleZoomIn = () => {
    setScale((value) => value + 1);
    setPosition(initialPosition);
  };

  const handleZoomOut = () => {
    if (scale > 1) {
      setScale((value) => value - 1);
    }
    setPosition(initialPosition);
  };

  const handleRotateRight = () => {
    setRotate((value) => value + 90);
  };

  const handleRotateLeft = () => {
    setRotate((value) => value - 90);
  };

  const wrapClassName = classnames({
    [`${prefixCls}-moving`]: isMoving,
  });
  const toolClassName = `${prefixCls}-operations-operation`;
  const iconClassName = `${prefixCls}-operations-icon`;
  const tools = [
    {
      icon: <CloseOutlined />,
      onClick: onClose,
      type: 'close',
    },
    {
      icon: <ZoomInOutlined />,
      onClick: handleZoomIn,
      type: 'zoomIn',
    },
    {
      icon: <ZoomOutOutlined />,
      onClick: handleZoomOut,
      type: 'zoomOut',
      disabled: scale === 1,
    },
    {
      icon: <RotateRightOutlined />,
      onClick: handleRotateRight,
      type: 'rotateRight',
    },
    {
      icon: <RotateLeftOutlined />,
      onClick: handleRotateLeft,
      type: 'rotateLeft',
    },
  ];

  const handleMouseUp: React.MouseEventHandler<HTMLBodyElement> = () => {
    if (visible && isMoving) {
      const width = imgRef.current.offsetWidth * scale;
      const height = imgRef.current.offsetHeight * scale;
      // eslint-disable-next-line @typescript-eslint/no-shadow
      const { left, top } = imgRef.current.getBoundingClientRect();
      const isRotate = rotate % 180 !== 0;

      setMoving(false);

      const fixState = getFixScaleEleTransPosition(
        isRotate ? height : width,
        isRotate ? width : height,
        left,
        top,
      );

      if (fixState) {
        setPosition({ ...fixState });
      }
    }
  };

  const handleMouseDown: React.MouseEventHandler<HTMLDivElement> = (event) => {
    if (event.button !== 0) return;
    event.preventDefault();
    event.stopPropagation();
    originPositionRef.current.deltaX = event.pageX - position.x;
    originPositionRef.current.deltaY = event.pageY - position.y;
    originPositionRef.current.originX = position.x;
    originPositionRef.current.originY = position.y;
    setMoving(true);
  };

  const handleMouseMove: React.MouseEventHandler<HTMLBodyElement> = (event) => {
    if (visible && isMoving) {
      setPosition({
        x: event.pageX - originPositionRef.current.deltaX,
        y: event.pageY - originPositionRef.current.deltaY,
      });
    }
  };

  const handleWheelMove: React.WheelEventHandler<HTMLBodyElement> = (event) => {
    if (!visible) return;
    event.preventDefault();
    const wheelDirection = event.deltaY;
    setLastWheelZoomDirection({ wheelDirection });
  };

  useEffect(() => {
    const { wheelDirection } = lastWheelZoomDirection;
    if (wheelDirection > 0) {
      handleZoomOut();
    } else if (wheelDirection < 0) {
      handleZoomIn();
    }
  }, [lastWheelZoomDirection]);

  useEffect(() => {
    let onTopMouseUpListener: { remove: () => void };
    let onTopMouseMoveListener: { remove: () => void };

    const onMouseUpListener = addEventListener(window, 'mouseup', handleMouseUp, false);
    const onMouseMoveListener = addEventListener(window, 'mousemove', handleMouseMove, false);
    const onScrollWheelListener = addEventListener(window, 'wheel', handleWheelMove, {
      passive: false,
    });

    try {
      if (window.top !== window.self) {
        onTopMouseUpListener = addEventListener(window.top, 'mouseup', handleMouseUp, false);
        onTopMouseMoveListener = addEventListener(window.top, 'mousemove', handleMouseMove, false);
      }
    } catch (error) {}

    return () => {
      onMouseUpListener.remove();
      onMouseMoveListener.remove();
      onScrollWheelListener.remove();

      /* istanbul ignore next */
      if (onTopMouseUpListener) onTopMouseUpListener.remove();
      /* istanbul ignore next */
      if (onTopMouseMoveListener) onTopMouseMoveListener.remove();
    };
  }, [visible, isMoving]);

  const { length } = images;

  const { lastIndex, showLeftOrRightSwitches } = useMemo(() => {
    return {
      lastIndex: length - 1,
      showLeftOrRightSwitches: length > 1,
    };
  }, [length]);

  return (
    <Dialog
      closable={false}
      afterClose={handleAfterClose}
      visible={visible}
      wrapClassName={wrapClassName}
      footer={null}
      prefixCls="ant-image-preview"
    >
      <ul className={`${prefixCls}-operations`}>
        {tools.map(({ icon, onClick, type, disabled }) => (
          <li
            className={classnames(toolClassName, {
              [`${prefixCls}-operations-operation-disabled`]: !!disabled,
            })}
            onClick={onClick}
            key={type}
          >
            {React.isValidElement(icon)
              ? React.cloneElement(icon, { className: iconClassName })
              : icon}
          </li>
        ))}
      </ul>
      <div
        className={`${prefixCls}-img-wrapper`}
        style={{
          transform: `translate3d(${position.x}px, ${position.y}px, 0)`,
        }}
      >
        <img
          onMouseDown={handleMouseDown}
          ref={imgRef}
          className={`${prefixCls}-img`}
          src={combinationSrc}
          alt={alt}
          style={{
            transform: `scale3d(${scale}, ${scale}, 1) rotate(${rotate}deg)`,
          }}
        />
      </div>
      {showLeftOrRightSwitches && (
        <div
          className={classnames(`${prefixCls}-switch-left`, {
            [`${prefixCls}-switch-left-disabled`]: currentPreviewIndex === 0,
          })}
          onClick={prevFn}
        >
          <LeftOutlined />
        </div>
      )}
      {showLeftOrRightSwitches && (
        <div
          className={classnames(`${prefixCls}-switch-right`, {
            [`${prefixCls}-switch-right-disabled`]: currentPreviewIndex === lastIndex,
          })}
          onClick={nextFn}
        >
          <RightOutlined />
        </div>
      )}
    </Dialog>
  );
};

export default FullScreenPreview;
